<?php

namespace service\impl;

use service\exception\ServiceException;
use service\ext\PageData;
use service\service\UserService;
use service\vo\user\User;
use think\db\exception\DbException;

class UserServiceImpl extends BaseImpl implements UserService
{
    private static string $modeName = 'user';

    /**
     * @inheritDoc
     */
    public function addUser(User $user): int
    {
        // TODO: Implement addUser() method.
        //判断用户是否存在
        $po = $this->getUserDb()
            ->where(self::$FIELD_USER_USERNAME, $user->getUsername())
            ->find();
        if (!empty($po)) {
            throw new ServiceException(self::$modeName, self::ERROR_USER_EXISTS);
        }
        if(!empty($user->getEmail())){
            //判断邮箱是否存在
            $po = $this->getUserDb()
                ->where(self::$FIELD_USER_EMAIL, $user->getEmail())
                ->find();
            if (!empty($po)) {
                throw new ServiceException(self::$modeName, self::ERROR_USER_EMAIL_EXISTS);
            }
        }
        if(!empty($user->getPhone())){
            //判断手机号是否存在
            $po = $this->getUserDb()
                ->where(self::$FIELD_USER_PHONE, $user->getPhone())
                ->find();
            if (!empty($po)) {
                throw new ServiceException(self::$modeName, self::ERROR_USER_PHONE_EXISTS);
            }
        }
        $data = [
            self::$FIELD_USER_PHONE => $user->getPhone() ?? "",
            self::$FIELD_USER_EMAIL => $user->getEmail() ?? "",
            self::$FIELD_USER_USERNAME => $user->getUsername(),
            self::$FIELD_USER_PASSWORD => md5($user->getPassword()),
//            self::$FIELD_USER_SEX => $user->getSex() ?? 0,
            self::$FIELD_USER_ADD_TIME => date('Y-m-d H:i:s'),
        ];
        return $this->getUserDb()->insert($data);
    }

    /**
     * @inheritDoc
     */
    public function editUser(User $user): int
    {
        // TODO: Implement editUser() method.
        //判断邮箱是否存在
        if(!empty($user->getEmail())){
            $po = $this->getUserDb()
                ->where([
                    self::$FIELD_USER_EMAIL, '=', $user->getEmail(),
                    self::$FIELD_COMMON_ID, '<>', $user->getId()
                ])
                ->find();
            if (!empty($po)) {
                throw new ServiceException(self::$modeName, self::ERROR_USER_EMAIL_EXISTS);
            }
        }
        //判断手机号是否存在
        if(!empty($user->getPhone())){
            $po = $this->getUserDb()
                ->where([
                    self::$FIELD_USER_PHONE, '=', $user->getPhone(),
                    self::$FIELD_COMMON_ID, '<>', $user->getId()
                ])
                ->find();
            if (!empty($po)) {
                throw new ServiceException(self::$modeName, self::ERROR_USER_PHONE_EXISTS);
            }
        }
        $data = [
            self::$FIELD_USER_STATUS => $user->getStatus(),
            self::$FIELD_USER_STATUS_REMARK => $user->getStatusRemark(),
        ];
        if(!empty($user->getSex())){
            $data[self::$FIELD_USER_SEX] = $user->getSex();
        }
        if(!empty($user->getPhone())){
            $data[self::$FIELD_USER_PHONE] = $user->getPhone();
        }
        if(!empty($user->getEmail())){
            $data[self::$FIELD_USER_EMAIL] = $user->getEmail();
        }
        if(!empty($user->getPassword())){
            $data[self::$FIELD_USER_PASSWORD] = md5($user->getPassword());
        }
        if(!empty($user->getBirthday())){
            $data[self::$FIELD_USER_BIRTHDAY] = $user->getBirthday();
        }
        return $this->getUserDb()->where(self::$FIELD_COMMON_ID, $user->getId())->update($data);
    }

    /**
     * @inheritDoc
     */
    public function deleteUser(int $userId): int
    {
        // TODO: Implement deleteUser() method.
        return $this->getUserDb()->delete($userId);
    }

    /**
     * @inheritDoc
     */
    public function deleteUsers(array $userIds): int
    {
        // TODO: Implement deleteUsers() method.
        return $this->getUserDb()->delete($userIds);
    }

    /**
     * @inheritDoc
     */
    public function changeUserPassword(int $userId, string $newPassword, string $oldPassword, bool $isCheckOldPassword): int
    {
        // TODO: Implement changeUserPassword() method.
        if($isCheckOldPassword){
            //检查旧密码
            $po = $this->getUserDb()
                ->where(self::$FIELD_COMMON_ID, $userId)
                ->findOrEmpty();
            if ($po->isEmpty()) {
                throw new ServiceException(self::$modeName, self::ERROR_USER_NOT_EXISTS);
            }
            if($po->getPassword() !== md5($oldPassword)){
                throw new ServiceException(self::$modeName, self::ERROR_USER_OLD_PWD_ERROR);
            }
        }
        //不检测旧密码或旧密码正确
        $data = [
            self::$FIELD_USER_PASSWORD => md5($newPassword)
        ];
        return $this->getUserDb()->where(self::$FIELD_COMMON_ID, $userId)->update($data);
    }

    /**
     * @inheritDoc
     */
    public function login(string $account, string $password): User
    {
        // TODO: Implement login() method.
        $map = [
            [
                [self::$FIELD_USER_USERNAME, '=', $account]
            ],
            [
                [self::$FIELD_USER_PHONE, '=', $account]
            ],
            [
                [self::$FIELD_USER_EMAIL, '=', $account]
            ]
        ];
        $po = $this->getUserDb()
            ->whereOr($map)
            ->where(self::$FIELD_USER_PASSWORD, md5($password))
            ->find();
        if (empty($po)) {
            throw new ServiceException(self::$modeName, self::ERROR_USER_LOGIN_FAILED);
        }
        return $this->getUserVoFromPo($po);
    }

    /**
     * @inheritDoc
     */
    public function incUserIntegral(int $userId, int $integral): int
    {
        // TODO: Implement incUserIntegral() method.
        return $this->getUserDb()
            ->where(self::$FIELD_COMMON_ID, $userId)
            ->inc(self::$FIELD_USER_INTEGRAL, $integral)
            ->update();
    }

    /**
     * @inheritDoc
     */
    public function decUserIntegral(int $userId, int $integral): int
    {
        // TODO: Implement decUserIntegral() method.
        return $this->getUserDb()
            ->where(self::$FIELD_COMMON_ID, $userId)
            ->dec(self::$FIELD_USER_INTEGRAL, $integral)
            ->update();
    }

    /**
     * @inheritDoc
     * @throws DbException
     */
    public function setUserVipExpireTime(int $userId, string $vipExpireTime): int
    {
        // TODO: Implement setUserVipExpireTime() method.
        return $this->getUserDb()
            ->where(self::$FIELD_COMMON_ID, $userId)
            ->update([
                self::$FIELD_USER_VIP_EXPIRE_TIME => $vipExpireTime
            ]);
    }

    /**
     * @inheritDoc
     */
    public function getUserById(int $userId): User
    {
        // TODO: Implement getUserById() method.
        $po = $this->getUserDb()
            ->where(self::$FIELD_COMMON_ID, $userId)
            ->find();
        if(empty($po)){
            throw new ServiceException(self::$modeName, self::ERROR_USER_NOT_EXISTS);
        }
        return $this->getUserVoFromPo($po);
    }

    /**
     * @inheritDoc
     *
     * @throws DbException
     */
    public function getUserByIds(array $userIds): array
    {
        // TODO: Implement getUserByIds() method.
        $voArr = [];
        $poArr = $this->getUserDb()
            ->whereIn(self::$FIELD_COMMON_ID, $userIds)
            ->select();
        foreach ($poArr as $po) {
            $voArr[] = $this->getUserVoFromPo($po);
        }
        return $voArr;
    }

    /**
     * @inheritDoc
     *
     * @throws DbException
     */
    public function checkUserExistsByUsername(string $username): bool
    {
        // TODO: Implement checkUserExistsByUsername() method.
        $po = $this->getUserDb()
            ->where(self::$FIELD_USER_USERNAME, $username)
            ->find();
        if(empty($po)){
            return false;
        }
        return true;
    }

    /**
     * @inheritDoc
     * @throws DbException
     */
    public function checkUserExistsByEmail(string $email): bool
    {
        // TODO: Implement checkUserExistsByEmail() method.
        $po = $this->getUserDb()
            ->where(self::$FIELD_USER_EMAIL, $email)
            ->find();
        if(empty($po)){
            return false;
        }
        return true;
    }

    /**
     * @inheritDoc
     * @throws DbException
     */
    public function checkUserExistsByPhone(string $phone): bool
    {
        // TODO: Implement checkUserExistsByPhone() method.
        $po = $this->getUserDb()
            ->where(self::$FIELD_USER_PHONE, $phone)
            ->find();
        if(empty($po)){
            return false;
        }
        return true;
    }

    /**
     * @inheritDoc
     * @throws DbException
     */
    public function searchUser(int $currentPage, int $pageSize, array $filterCriteria, array $sorterCriteria): PageData
    {
        // TODO: Implement searchUser() method.
        $filter = [];
        if (!empty($filterCriteria)) {
            foreach ($filterCriteria as $key => $value) {
                if (strcasecmp($key, self::$FILTER_NAME) == 0) {
                    //用户名
                    $filter[] = [self::$FIELD_USER_USERNAME, "like", "%{$value}%"];
                } else if (strcasecmp($key, self::$FILTER_EMAIL) == 0) {
                    //邮箱
                    $filter[] = [self::$FIELD_USER_EMAIL, "like", "%{$value}%"];
                } else if (strcasecmp($key, self::$FILTER_PHONE) == 0) {
                    //手机号
                    $filter[] = [self::$FIELD_USER_PHONE, "like", "%{$value}%"];
                } else if (strcasecmp($key, self::$FILTER_STATUS) == 0) {
                    //状态
                    $filter[] = [self::$FIELD_USER_STATUS, "=", $value];
                } elseif (strcasecmp($key, self::$FILTER_ADD_TIME) == 0) {
                    //时间
                    $betweenTime = makeBetween($value['start'], $value['end']);
                    $filter[] = [self::$FIELD_USER_ADD_TIME, $betweenTime[0], $betweenTime[1]];
                }
            }
        }

        //构建排序条件
        $sort = [];
        if (!empty($sorterCriteria)) {
            foreach ($sorterCriteria as $key => $value) {
                if (strcasecmp($key, self::$SORT_ID) == 0) {
                    $sort[self::$FIELD_COMMON_ID] = $value ? self::$SORT_VALUE_ASC : self::$SORT_VALUE_DESC;
                }
            }
        }

        $count = $this->getUserDb()
            ->where($filter)
            ->count();
        $list = $this->getUserDb()
            ->where($filter)
            ->order($sort)
            ->limit($pageSize)
            ->page($currentPage)
            ->select();

        $dataList = [];
        foreach ($list as $po) {
            $dataList[] = $this->getUserVoFromPo($po);
        }

        $pageData = new PageData();
        $pageData->setData($dataList);
        $pageData->setCount($count);

        return $pageData;
    }

    private function getUserVoFromPo($po): User
    {
        $vo = new User();
        $vo->setId($po[self::$FIELD_COMMON_ID]);
        $vo->setUsername($po[self::$FIELD_USER_USERNAME]);
        $vo->setEmail($po[self::$FIELD_USER_EMAIL]);
        $vo->setPhone($po[self::$FIELD_USER_PHONE]);
        $vo->setBirthday($po[self::$FIELD_USER_BIRTHDAY]);
        $vo->setStatus($po[self::$FIELD_USER_STATUS]);
        $vo->setStatusRemark($po[self::$FIELD_USER_STATUS_REMARK]);
        $vo->setAddTime($po[self::$FIELD_USER_ADD_TIME]);
        $vo->setIntegral($po[self::$FIELD_USER_INTEGRAL]);
        $vo->setSex($po[self::$FIELD_USER_SEX]);
        $vo->setVipExpireTime($po[self::$FIELD_USER_VIP_EXPIRE_TIME]);
        return $vo;
    }
}